No hay prompts todavía
{searchTerm || selectedTag ? "No se encontraron resultados para tu búsqueda." : "Comienza creando tu primera colección de prompts para IA."}
{!searchTerm && !selectedTag && ( )}{prompt.title}
{prompt.content}
import React, { useState, useEffect, useMemo } from 'react'; import { Plus, Search, Copy, Trash2, Edit2, Save, X, Tag, Terminal, Cpu, Check } from 'lucide-react'; import { initializeApp } from 'firebase/app'; import { getAuth, onAuthStateChanged, signInAnonymously, signInWithCustomToken } from 'firebase/auth'; import { getFirestore, collection, addDoc, updateDoc, deleteDoc, doc, onSnapshot, serverTimestamp, query, orderBy } from 'firebase/firestore'; // --- Configuración de Firebase --- const firebaseConfig = JSON.parse(__firebase_config); const app = initializeApp(firebaseConfig); const auth = getAuth(app); const db = getFirestore(app); const appId = typeof __app_id !== 'undefined' ? __app_id : 'default-app-id'; // --- Componente Principal --- export default function PromptManager() { const [user, setUser] = useState(null); const [prompts, setPrompts] = useState([]); const [loading, setLoading] = useState(true); const [isModalOpen, setIsModalOpen] = useState(false); const [currentPrompt, setCurrentPrompt] = useState(null); // Para editar o crear const [searchTerm, setSearchTerm] = useState(''); const [selectedTag, setSelectedTag] = useState(null); const [toast, setToast] = useState(null); // 1. Autenticación useEffect(() => { const initAuth = async () => { try { if (typeof __initial_auth_token !== 'undefined' && __initial_auth_token) { await signInWithCustomToken(auth, __initial_auth_token); } else { await signInAnonymously(auth); } } catch (error) { console.error("Error en autenticación:", error); } }; initAuth(); const unsubscribe = onAuthStateChanged(auth, (currentUser) => { setUser(currentUser); }); return () => unsubscribe(); }, []); // 2. Carga de Datos (Firestore) useEffect(() => { if (!user) return; // Ruta segura: artifacts/{appId}/users/{userId}/prompts const promptsCollection = collection(db, 'artifacts', appId, 'users', user.uid, 'prompts'); // NOTA: Firestore requiere índices para orderBy compuesto, así que traemos todo y ordenamos en memoria // o usamos una query simple. Aquí usamos snapshot simple. const unsubscribe = onSnapshot(promptsCollection, (snapshot) => { const loadedPrompts = snapshot.docs.map(doc => ({ id: doc.id, ...doc.data() })); // Ordenar en cliente por fecha (más reciente primero) loadedPrompts.sort((a, b) => { const dateA = a.createdAt?.toDate ? a.createdAt.toDate() : new Date(0); const dateB = b.createdAt?.toDate ? b.createdAt.toDate() : new Date(0); return dateB - dateA; }); setPrompts(loadedPrompts); setLoading(false); }, (error) => { console.error("Error al cargar prompts:", error); setLoading(false); } ); return () => unsubscribe(); }, [user]); // --- Lógica de Negocio --- const handleSave = async (e) => { e.preventDefault(); if (!user) return; const title = e.target.title.value; const content = e.target.content.value; const tagsInput = e.target.tags.value; // Convertir tags string a array y limpiar espacios const tags = tagsInput.split(',').map(t => t.trim()).filter(t => t.length > 0); const promptData = { title, content, tags, updatedAt: serverTimestamp() }; try { if (currentPrompt?.id) { // Editar existente const promptRef = doc(db, 'artifacts', appId, 'users', user.uid, 'prompts', currentPrompt.id); await updateDoc(promptRef, promptData); showToast("Prompt actualizado correctamente"); } else { // Crear nuevo const promptsCollection = collection(db, 'artifacts', appId, 'users', user.uid, 'prompts'); await addDoc(promptsCollection, { ...promptData, createdAt: serverTimestamp() }); showToast("Prompt guardado correctamente"); } closeModal(); } catch (error) { console.error("Error al guardar:", error); showToast("Error al guardar", "error"); } }; const handleDelete = async (id) => { if (!user || !window.confirm("¿Estás seguro de que quieres eliminar este prompt?")) return; try { const promptRef = doc(db, 'artifacts', appId, 'users', user.uid, 'prompts', id); await deleteDoc(promptRef); showToast("Prompt eliminado"); } catch (error) { console.error("Error al eliminar:", error); } }; const openNewModal = () => { setCurrentPrompt(null); setIsModalOpen(true); }; const openEditModal = (prompt) => { setCurrentPrompt(prompt); setIsModalOpen(true); }; const closeModal = () => { setIsModalOpen(false); setCurrentPrompt(null); }; // Función de copiado robusta para iframes const copyToClipboard = (text) => { const textArea = document.createElement("textarea"); textArea.value = text; textArea.style.position = "fixed"; textArea.style.left = "-9999px"; document.body.appendChild(textArea); textArea.focus(); textArea.select(); try { document.execCommand('copy'); showToast("Copiado al portapapeles"); } catch (err) { console.error('Error al copiar', err); showToast("Error al copiar", "error"); } document.body.removeChild(textArea); }; const showToast = (message, type = 'success') => { setToast({ message, type }); setTimeout(() => setToast(null), 3000); }; // --- Filtrado --- const filteredPrompts = useMemo(() => { return prompts.filter(p => { const matchesSearch = (p.title?.toLowerCase() || '').includes(searchTerm.toLowerCase()) || (p.content?.toLowerCase() || '').includes(searchTerm.toLowerCase()); const matchesTag = selectedTag ? p.tags?.includes(selectedTag) : true; return matchesSearch && matchesTag; }); }, [prompts, searchTerm, selectedTag]); // Obtener todos los tags únicos const allTags = useMemo(() => { const tags = new Set(); prompts.forEach(p => p.tags?.forEach(t => tags.add(t))); return Array.from(tags).sort(); }, [prompts]); // --- Renderizado --- if (loading) { return (
{searchTerm || selectedTag ? "No se encontraron resultados para tu búsqueda." : "Comienza creando tu primera colección de prompts para IA."}
{!searchTerm && !selectedTag && ( )}{prompt.content}